package com.xjrh.traintravel.collector.netty.handler;

import javax.annotation.Resource;
import java.util.Calendar;

import com.xjrh.common.core.utils.ObjectUtils;
import com.xjrh.traintravel.collector.api.BusinessTrainService;
import com.xjrh.traintravel.collector.api.param.Equipment;
import com.xjrh.traintravel.collector.common.CRC16M;
import com.xjrh.traintravel.collector.common.CodeConvertor;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementCommandEnum;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementConstant;
import com.xjrh.traintravel.collector.netty.coder.command.AgreementStructure;
import com.xjrh.traintravel.collector.netty.command.access.AccessData;
import com.xjrh.traintravel.collector.runner.NettyClientManager;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 客户端接入指令处理类
 *  <p>
 *      包括：
 *          1-心跳
 *          2-登录（设备接入，保存连接）
 *  </p>
 *
 * @author snps
 * @create 2022-01-17 14:04
 * @describe
 **/
@Component
@Slf4j
public class AccessAgreementHandler extends BaseAgreementHandler {

    // 老协议-登录指令长度：16、新指令-登录指令长度：18
    private final int FS3_AGREEMENT_SIZE = 16;
    private final int QD6_AGREEMENT_SIZE = 18;

    @Resource
    private NettyClientManager nettyClientManager;

    @Resource
    private BusinessTrainService businessTrainService;


    /**
     * 收到-心跳
     * @param agreement 收到的消息
     * @param channel 客户端连接通道
     */
    public void heartbeat(AgreementStructure agreement, Channel channel) {
        // log.warn("收到-设备【{}】心跳", agreement.getAddr() + "--" + channel.remoteAddress());
    }

    /**
     * 回复-心跳
     * @param agreement 收到的消息
     * @param channel 客户端连接通道
     */
    public void replyHeartbeat(AgreementStructure agreement, Channel channel) {
        /* 构造命令 */
        AgreementStructure replyAgreement = new AgreementStructure();

        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_80.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(agreement.getSeq());
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 数据长度(0)
        replyAgreement.setLen(CodeConvertor.intToHexString(0, 2));
        // 数据
        // replyAgreement.setData(null);
        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        /* 发送命令 */
        super.sendCommand(replyAgreement, channel);
    }


    /************************************************************
     * 收到-登录（设备接入，保存连接）
     * @param agreement 收到的消息
     * @param channel 客户端连接通道
     */
    public void login(AgreementStructure agreement, Channel channel) {
        // TODO 保存客户端的连接，以备后续通信时使用（此处可以增加连接安全验证，保证受信的连接才可以进入）
        AccessData accessData = new AccessData();

        // 获取：车序号（1-6车）
        int carriageSeq = Integer.parseInt(agreement.getSeq(), 16);
        nettyClientManager.saveClientChannelSeq(agreement.getAddr(), carriageSeq);

        // 处理协议内容
        accessData.setCommonNo(agreement.getData().substring(0, 2));
        accessData.setEquipmentType(Integer.parseInt(agreement.getData().substring(2, 4), 16));
        accessData.setEquipmentNo(Integer.parseInt(agreement.getData().substring(4, 6), 16));
        accessData.setPart1No(CodeConvertor.hexString2String(agreement.getData().substring(6, 12)));
        accessData.setPart2No(CodeConvertor.hexString2String(agreement.getData().substring(12, 18)));
        accessData.setPart3No(CodeConvertor.hexString2String(agreement.getData().substring(18, 24)));

        // 根据“协议内容长度：软件版本、硬件版本长度”做新、老指令兼容（老指令长度：16、新指令长度：18）
        int agreementSize = Integer.parseInt(agreement.getLen(), 16);

        String version = "";
        if (agreementSize == FS3_AGREEMENT_SIZE) {
            // log.warn("老协议，登录指令长度：{}", agreementSize);
            accessData.setSoftwareVersion(agreement.getData().substring(24, 28));
            accessData.setHardwareVersion(agreement.getData().substring(28, 32));
            version = accessData.getSoftwareVersion();

            // 转换版本号
            if (!ObjectUtils.isEmpty(accessData.getSoftwareVersion())) {
                StringBuilder sbuVersion = new StringBuilder();
                sbuVersion.append(Integer.parseInt(version.substring(0, 2), 16));
                sbuVersion.append(".");
                sbuVersion.append(Integer.parseInt(version.substring(2), 16));
                version = sbuVersion.toString();
            }
        } else if (agreementSize == QD6_AGREEMENT_SIZE) {
            // log.warn("新协议，登录指令长度：{}", agreementSize);
            accessData.setSoftwareVersion(agreement.getData().substring(24, 30));
            accessData.setHardwareVersion(agreement.getData().substring(30, 36));
            version = accessData.getSoftwareVersion();

            // 转换版本号
            if (!ObjectUtils.isEmpty(accessData.getSoftwareVersion())) {
                StringBuilder sbuVersion = new StringBuilder();
                sbuVersion.append(Integer.parseInt(version.substring(0, 2), 16));
                sbuVersion.append(".");
                sbuVersion.append(Integer.parseInt(version.substring(2, 4), 16));
                sbuVersion.append(".");
                sbuVersion.append(Integer.parseInt(version.substring(4, 6), 16));
                version = sbuVersion.toString();
            }
        } else {
            log.error("登录指令长度：{}，长度错误，丢弃！");
            return;
        }

        // 保存 客户端连接
        AttributeKey<String> attrEquipmentId = AttributeKey.valueOf(BaseAgreementHandler.ATTR_KEY_EQUIPMENT_ID);
        channel.attr(attrEquipmentId).set(agreement.getAddr());
        log.warn("收到-设备【{}】登录(接入)，软件版本：{}，设备型号：{}", channel.attr(attrEquipmentId).get(), version, accessData.getEquipmentType());
        nettyClientManager.saveClientChannel(channel.attr(attrEquipmentId).get(), channel);

        // 修改客户端在线状态
        try {
            // businessTrainService.setNetStatus(channel.attr(attrEquipmentId).get(), 1, version);
            Equipment equipment = new Equipment();
            equipment.setMacAddr(channel.attr(attrEquipmentId).get());
            equipment.setEquipmentTypeId(new Long(accessData.getEquipmentType()));
            equipment.setVersion(version);
            equipment.setNetStatus(1);
            /*equipment.setLineNo(accessData.getPart1No());
            equipment.setTrainNo(accessData.getPart2No());
            equipment.setCarriageNo(accessData.getPart3No());*/
            businessTrainService.updateByMacAddr(equipment);
        } catch (Exception e) {
            log.error("通过mac地址修改设备信息，失败！");
        }
    }

    /**
     * 回复-登录
     * @param agreement 收到的消息
     * @param channel 客户端连接通道
     */
    public void replyLogin(AgreementStructure agreement, Channel channel) {
        // 获取当前时间（YYMMDDHHMMSS）
        StringBuilder sbuTime = new StringBuilder("");
        Calendar calendar = Calendar.getInstance();
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.YEAR)- 2000, 1));
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.MONTH) + 1, 1));
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.DAY_OF_MONTH), 1));
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.HOUR_OF_DAY), 1));
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.MINUTE), 1));
        sbuTime.append(CodeConvertor.intToHexString(calendar.get(Calendar.SECOND), 1));
        String time = sbuTime.toString();

        /* 构造命令 */
        AgreementStructure replyAgreement = new AgreementStructure();
        // 前导码(4)
        replyAgreement.setPc(AgreementConstant.PC_VALUE);
        // 帧头(1)
        replyAgreement.setSd(AgreementConstant.SD_VALUE);
        // 控制(1)
        replyAgreement.setFc(AgreementCommandEnum.R_81.getValue());
        // MAC地址(6)
        replyAgreement.setAddr(agreement.getAddr());
        // 序号(1)
        // replyAgreement.setSeq(agreement.getSeq());
        replyAgreement.setSeq(super.getEquipmentSeq(replyAgreement.getAddr()));
        // 数据长度(N)
        replyAgreement.setLen(CodeConvertor.intToHexString(1 + time.length()/2, 2));
        // 数据
        String data = "01" + time;
        replyAgreement.setData(data);

        // 校验(2)
        String crcValue = CRC16M.calculateCrc(replyAgreement);
        replyAgreement.setFcs(crcValue);
        // 帧尾(1)
        replyAgreement.setFs(AgreementConstant.FS_VALUE);

        /* 发送命令 */
        super.sendCommand(replyAgreement, channel);
    }

}